const gjjTokenUrl   = "https://t.51gjj.com/gjj/getToken";
const getOrderSnUrl = "https://t.51gjj.com/gjj/getOrderSn";
const getGjjH5Url   = "https://t.51gjj.com/gjj";
const gjjDataUrl    = "http://b.jianbing.com/gjj_v3/gjj/fetch_manual";
const getGjjDataUrl = "https://t.51gjj.com/gjj/getGjjData";

const NAME_AES_KEY = 'zt2i6cea0fceabb063e3961gg67op345';//name、id
const PASS_AES_KEY = 'f1e24cea0fceaaa063e3961ff187f1e6';//password

var myRedis = require('./myRedis').config('6379', '127.0.0.1');
var myAxios =  require('./myAxios');

var fs          =  require('fs');
var config      =  require('config');
var NodeRSA     =  require('node-rsa');
var express     =  require('express');
var querystring =  require('querystring');
// var nodeDB      =  require('./db');
var md5         =  require('md5');
var url         =  require('url');
var request     =  require('request');
var myCrypto    =  require('crypto');
var myDB        = require('./myDB');

var BS = {
    parCfg: new Object(),
    tokenName: "",
    lockName: "",
    getTokenToRedis:async function (expiresTime,refresh) {
        expiresTime = expiresTime || 7200;
        refresh = refresh || false;
        let token = null;

        let insRedis = myRedis.create();
        let reloading = function (){
            let i = 0;
            return new Promise(resolve=>{
                let myTimer = setInterval(
                    async function(){
                        token = await insRedis.get(this.tokenName);
                        //console.error(token)
                        console.error('loading modify '+this.tokenName+':'+token);
                        if(token!==null || i>30){
                            clearTimeout(myTimer);
                            resolve(token);
                        }
                    },
                    1000
                )}
            );
        }

        token = await insRedis.get(this.tokenName);
        //console.log('old token is:' + token);

        if (token === null || refresh) {
            let ifSet = await insRedis.set(this.lockName, 'lock', 'EX', 30, 'NX');
            console.error('ifLock ' + (ifSet?'正在取token...':'等待token...'));
            if (ifSet) {
                // //获取token
                let data = [];
                data['timestamp'] = +new Date;
                data['appKey'] = this.parCfg.reptileAppKey;
                let appSecret = this.parCfg.reptileAppSecret;
                let sign = this.createSign(data,appSecret);
                //token参数
                let params = {
                    "sign":sign,
                    "params":{
                        "appKey":data['appKey'],
                        "timestamp":data['timestamp']
                    }
                }

                console.log('[serverBase3/getToken] params='+JSON.stringify(params));
                let result = await myAxios.post(gjjTokenUrl,params,{headers:{'Content-Type':'application/json'}});
                if(result){
                    if(result.data.code==0){
                        //写入token
                        token = result.data.data.token;
                        await insRedis.set(this.tokenName, token, 'EX', expiresTime);
                        //复读
                        // token = await insRedis.get(tokenName);
                    }
                }
                if(typeof token!='string'){
                    insRedis.del(this.lockName);
                    token = await reloading();
                }

            } else {
                //遇到锁|等待
                token = await reloading();
            }
        }
        //console.log('[serverBase3/getToken] new token is:'+this.tokenName+'='+ token);
        return token;
    },
    getOrder:async function (){
        let data = [];
        data['timestamp'] = +new Date;
        data['appKey']    = this.parCfg.reptileAppKey;
        data['token']     = await this.getTokenToRedis();
        let appSecret     = this.parCfg.reptileAppSecret;
        let sign = this.createSign(data,appSecret);

        let params = {
            "sign":sign,
            "params":{
                "appKey":data['appKey'],
                "timestamp":data['timestamp'],
                "token":data['token']
            }
        }

        let orderSn = null;
        let result = await myAxios.post(getOrderSnUrl,params,{headers:{'Content-Type':'application/json'}});
        if(result){
            if(result.data.code==0){
                //写入token
                orderSn = result.data.data.orderSn;
                return orderSn;
            }else if(result.data.msg=='无效的token'){
                console.error('【'+this.parCfg.name+'】【getOrder】无效的token，已经重试，稍后再请求一次');
                await this.getTokenToRedis(7200, true);
            }
        }

        throw "get orderSn fail";
    },
    createOldToken:function (size){
        if(!size){size=32;}
        var token = this.randomString(size);
        return token;
    },
    createOldOpenid:function (num){
        if(!num){num=0;}
        var r = new Array('Q', 'w', 'E', '8', 'a', 'S', '2', 'd', 'Z', 'x', '9', 'c', '7', 'p', 'O', '5', 'i', 'K', '3', 'm', 'j', 'U', 'f', 'r', '4', 'V', 'y', 'L', 't', 'N', '6', 'b', 'g', 'H');
        var b = new Array('q', 'W', 'e', 'A', 's', 'D', 'z', 'X', 'C', 'P', 'o', 'I', 'k', 'M', 'J', 'u', 'F', 'R', 'v', 'Y', 'T', 'n', 'B', 'G', 'h');
        var l = r.length;
        var s = 12;
        var buf = new Array();
        var charPos = 32;
        for(var i=0;i<charPos;i++){
            buf[i]=' ';
        }
        while (Math.round(num / l) > 0) {
            buf[--charPos] = r[Math.round(num % l)];
            num /= l;
        }
        buf[--charPos] = r[Math.round(num % l)];
        buf = buf.join('');
        var str = buf.substr(charPos, (32 - charPos));
        //不够长度的自动随机补全
        if ( str.length < s) {
            var sb = '';
            for (i = 0; i < s - str.length; i++) {
                sb += b[Math.round(Math.random()*(b.length-1))];
            }
            str += sb;
        }
        return str;
    },
    jsonPost:async function (serUrl, params){
        let result = await myAxios.post(serUrl,params,{headers: {'Content-Type': 'application/json'}});
        return result.data;
    },
    getQuest:async function (serUrl, params){
        return await myAxios.get(serUrl,params)
    },
    randomString:function  (size){
        if(!size){size=32;}
        var a = "-_0987654321asdfghjklzxcvbnmqwertyuiopASDFGHJKLZXCVBNMQWERTYUIOP";
        var len = a.length;
        var result = '';
        for(var i=0; i<size; i++) {
            result += a[0+Math.round(Math.random()*len)];
        }
        return result;
    },
    urlBase64Encode:function (str) {
        let buf = new Buffer(str);
        let base64str = buf.toString('base64');
        base64str = base64str.replace(/\+/g,'-');
        base64str = base64str.replace(/\//g,'_');
        base64str = base64str.replace(/=/g,'');
        console.log(base64str);
        return base64str;
    },
    urlBase64Decode:function (base64str) {
        base64str = base64str.replace(/-/g,'+');
        base64str = base64str.replace(/_/g,'/');
        let mod4 = base64str.length % 4;
        if(mod4){
            base64str += '===='.substr(mod4);
        }
        let buf = new Buffer(base64str,'base64');
        let str = buf.toString('utf8');
        return str;
    },
    decodeName:function (str){},
    encodeName:function (str){},
    decodePass:function (str,userSid){},
    encodePass:function (str,userSid){},
    myRsaEncrypt:function (str, publicKeyFileName){
        let rsaEncodeData = "";
        try {

            let rsaPublicFile  = __projectDir+'/ca/'+publicKeyFileName;
            let rsaPublicKeyStr = fs.readFileSync(rsaPublicFile).toString('ascii');

            let rsaResource = new NodeRSA(rsaPublicKeyStr);
            rsaEncodeData = rsaResource.encrypt(str,'base64',rsaResource);
            rsaEncodeData = urlBase64Encode(rsaEncodeData);
        }catch(err) {
            console.log('rsa加密: '+err);
        }
        return rsaEncodeData;
    },
    myRsaDecrypt:function (rsaEncodeData, privateKeyFileName){
        var rsaDecodeData = "";

        try {
            rsaEncodeData = urlBase64Decode(rsaEncodeData);

            let rsaPrivateFile  = __projectDir+'/ca/'+privateKeyFileName;
            let rsaPrivateKeyStr = fs.readFileSync(rsaPrivateFile).toString('ascii');
            let rsaResource = new NodeRSA(rsaPrivateKeyStr);
            rsaDecodeData = rsaResource.decrypt(rsaEncodeData,'utf8');
        }catch(err){
            console.log('rsa解密: '+err);
        }
        return rsaDecodeData;
    },
    _myRsaEncrypt:function (str, rsaPublicKeyStr){
        str = urlBase64Encode(str);
        var rsaEncodeData = "";
        try {
            var publickey = new NodeRSA(rsaPublicKeyStr);
            rsaEncodeData = publickey.encrypt(str,'base64');
        }catch(err) {
            console.log('rsa加密: '+err);
        }
        return rsaEncodeData;
    },
    _myRsaDecrypt:function (rsaEncodeData, rsaPrivateKeyStr){
        //rsaPrivateKeyStr = rsaPrivateKeyStr.replace(/\n/g,'');
        //rsaPrivateKeyStr = rsaPrivateKeyStr.replace(/\r/g,'');
        let privateKey = {
            "key":rsaPrivateKeyStr,
            "passphrase":"",
            "padding":myCrypto.constants.RSA_NO_PADDING
        }
        // rsaEncodeData = base64Decode(rsaEncodeData);
        var rsaDecodeData = "";
        try {
            // let privatekey = new NodeRSA(rsaPrivateKeyStr);
            // rsaDecodeData = privatekey.decrypt(rsaEncodeData,'utf8');

            let buf = new Buffer(rsaEncodeData);
            let step = 64;
            let box = new Array();
            let x = 0;
            for(var i=0; i<buf.length; i+=step){
                box[x] = myCrypto.privateDecrypt(privateKey,new Buffer(rsaEncodeData.substr(i,step)));
                ++x;
            }
            rsaDecodeData = box.join('');

            //rsaDecodeData = myCrypto.privateDecrypt(privateKey,new Buffer(rsaEncodeData));
        }catch(err){
            console.log('rsa解密: '+err);
        }
        return rsaDecodeData;
    },
    getParams:function (req, key, def){
        var params = "";
        if(typeof req.body[key]!='undefined'){
            params = req.body[key];
        }else if(typeof url.parse(req.url, true).query[key]!='undefined'){
            params = url.parse(req.url, true).query[key];
        }
        if(!params){
            params = def;
        }
        return params;
    },
    getValue:function (data, key, def){
        let res;
        if(typeof def!='undefined'){
            res = def;
        }
        if(typeof data!='undefined' && typeof data[key]!='undefined'){
            res = data[key];
        }

        return res;
    },
    createSign:function (params,appSecret,version){
        var keys = new Array();
        var i = 0;

        for(x in params){
            if(params[x]){
                keys[i] = x;
                ++i;
            }
        }
        keys.sort();
        // console.log(keys);
        var sp = '';
        var stringA = '';
        var value;
        for (var x=0; x<keys.length; x++){
            if(keys[x]=='sign' || keys[x]=='signType'){
                continue;
            }
            value = params[keys[x]];

            if(value){
                stringA += sp + keys[x] + '=' + value;
                sp = '&';
            }
        }
        //差异appSecret  &  appsecret
        let appSecretKey;
        if(!version){
            //爬虫端
            appSecretKey = 'appSecret';
        }else{
            //原来服务端
            appSecretKey = 'appsecret';
        }
        stringA += sp + appSecretKey+'=' + appSecret;
        var md5StringA = md5(stringA);
        return md5StringA.toUpperCase();
    },
    notify:async function (url,params){
        console.log('【'+this.parCfg.name+'/notify】url='+url+' params='+JSON.stringify(params));

        //是否加密通知
        //判断依据是否有合作方预留的公钥
        if(this.parCfg.partnerPublicKey){
            if(typeof params=='object'){
                params = JSON.stringify(params);
            }
            let rsaPublicFileName  = __projectDir+'/ca/'+this.parCfg.partnerPublicKey;
            let rsaPublicKeyStr = fs.readFileSync(rsaPublicFileName).toString('ascii');
            params = myRsaEncrypt(params,rsaPublicKeyStr);

            params = JSON.parse(params);
        }

        let result = await myAxios.post(url,params,{headers: {'Content-Type': 'application/json'}});
        if(result){
            if(result.data){
                let data = result.data;
                if(JSON.stringify(data).indexOf('200')==-1){
                    console.error('【'+this.parCfg.name+'/notify】状态码不对 '+JSON.stringify(data));
                }else{
                    console.log('【'+this.parCfg.name+'/notify】'+JSON.stringify(data));
                }
                return result;
            }else{
                console.error('【'+this.parCfg.name+'/notify】缺少 data'+JSON.stringify(result));
            }
        }else{
            console.error('【'+this.parCfg.name+'/notify】 发送失败 post fail '+JSON.stringify(result));
        }
        return false;
    },
    getGjjSign:async function (orderSn){
        let gjjData = await this.getGjjData(orderSn);
        if(gjjData){
            // console.log(data);
            if(gjjData.code==0){
                // let name   = "";
                let ID     = "";
                let name   = "";
                let cityId = "";
                let ifLoan = false;

                if(gjjData.data.gjjData.data.gjj_data){
                    let gjjDataList = gjjData.data.gjjData.data.gjj_data;
                    let loanDataList = gjjData.data.gjjData.data.loan_data;
                    if(gjjDataList.length>0){
                        for(let i=0; i<gjjDataList.length; i++){
                            if(gjjDataList[i].gjj_account_analyzed_data.newest_account == 1){
                                ID     =  gjjDataList[i].gjj_brief.ID;
                                name   =  gjjDataList[i].gjj_brief.name;
                                cityId =  gjjData.data.gjjData.cid;
                            }
                        }
                    }
                    if(loanDataList.length>0){
                        ifLoan = true;
                    }
                }

                let params = new Object();
                //参与md5的参数
                params.ID     = ID;
                params.cityId = cityId;
                let gjjMD5 =  this.paramsSign(params);

                //有用到的参数
                params.name   = name;
                params.ifLoan = ifLoan;

                return {gjjDataSign:gjjMD5,params:params};
            }else{
                console.error(gjjData.msg);
                return ''
            }
        }else{
            console.error('getGjjSign fail');
            return '';
        }
    },
    getGjjData:async function (orderSn){
        let params = {
            appKey:this.parCfg.reptileAppKey,
            timestamp:+new Date,
            token:await this.getTokenToRedis(),
            orderSn:orderSn
        }
        let sign = this.createSign(params,this.parCfg.reptileAppSecret);
        let option = {
            "type":'gjj',
            "sign":sign,
            "params":params
        }
        return await this.jsonPost(getGjjDataUrl,option);
    },
    paramsSign :function (params){
        let keys = new Array();
        let i = 0;
        for(x in params){
            if(params[x]){
                keys[i] = x;
                ++i;
            }
        }
        keys.sort();
        let sp = '';
        let stringA = '';
        let value;
        for (var x=0; x<keys.length; x++){

            value = params[keys[x]];

            if(value){
                stringA += sp + keys[x] + '=' + value;
                sp = '&';
            }
        }
        let md5StringA = md5(stringA);
        let gjjMD5 =  md5StringA.toUpperCase();
        return gjjMD5
    },
    getLocalInfo: function (familyName,paramsName){
        let interfaces = require('os').networkInterfaces();
        //console.log(interfaces);
        for(var devName in interfaces){

            let iface = interfaces[devName];

            for(var i=0;i<iface.length;i++){
                let alias = iface[i];
                //familyName = 'IPv4'
                if(alias.family === familyName && alias.address !== '127.0.0.1' && alias.address !== '172.27.0.3' && !alias.internal){
                    return alias[paramsName];
                }
            }

        }
    },
    config:async function(cid){
        let Obj = this;
        let localCfg = new Object();
        let DBParCfg = await myDB.getDB("nodeGjjDB").getRowAsync('select * from cfg_partner where cid=?',[cid]);
        // for(x in parCfg){
        //     if(DBParCfg[x]){
        //         localCfg[x] = DBParCfg[x];
        //     }else{
        //         localCfg[x] = parCfg[x];
        //     }
        // }
        Obj.parCfg = DBParCfg;
        Obj.tokenName = "partner_token_"+cid;
        Obj.lockName  = "token_lock_"+cid;
        return Obj;
    }
}

module.exports = BS;